<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>发电机房监测</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
    <style>
        body {
            font-family: 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
            background: #f5f7fa;
            margin: 0;
            padding: 0;
        }
        .container {
            max-width: 1200px;
            margin: 40px auto;
            background: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 12px 0 rgba(0,0,0,.08);
            padding: 32px 24px 24px 24px;
        }
        .title {
            font-size: 22px;
            font-weight: bold;
            color: #1565C0;
            margin-bottom: 24px;
        }
        .section {
            margin-bottom: 28px;
        }
        .el-card__header {
            font-size: 16px;
            font-weight: 600;
            color: #303133;
        }
        .stat-row {
            display: flex;
            gap: 24px;
            margin-bottom: 16px;
        }
        .stat-card {
            flex: 1;
        }
        .device-table {
            margin-top: 12px;
        }
        .alert-table {
            margin-top: 12px;
        }
        .point-map {
            width: 100%;
            height: 320px;
            background: #f5f7fa url('generator-room-bg.png') center/cover no-repeat;
            border: 1px solid #ebeef5;
            border-radius: 8px;
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #909399;
            font-size: 18px;
        }
        .point-marker {
            position: absolute;
            width: 32px;
            height: 32px;
            background: #1565C0;
            color: #fff;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            cursor: pointer;
            border: 2px solid #fff;
            box-shadow: 0 2px 8px rgba(21,101,192,0.15);
        }
        @media (max-width: 900px) {
            .stat-row {
                flex-direction: column;
                gap: 12px;
            }
        }
        .dashboard-flex {
            display: flex;
            justify-content: center;
            align-items: stretch;
            gap: 32px;
        }
        .dashboard-card {
            transition: transform 0.25s cubic-bezier(.4,2,.6,1);
            will-change: transform;
        }
        .dashboard-num {
            font-size: 22px;
            font-weight: bold;
            transition: color 0.3s;
        }
        .dashboard-anim {
            animation: fadeInUp 0.8s cubic-bezier(.4,2,.6,1);
            display: inline-block;
        }
        @keyframes fadeInUp {
            from { opacity: 0; transform: translateY(30px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .dashboard-vertical {
            display: flex;
            flex-direction: column;
            gap: 0;
        }
        .alarm-stat-card {
            background: linear-gradient(90deg, #f5f7fa 60%, #e3f2fd 100%);
            border-radius: 14px;
            box-shadow: 0 2px 12px 0 rgba(21,101,192,0.06);
            padding-bottom: 18px;
        }
        .alarm-stat-title {
            font-size: 20px;
            font-weight: bold;
            color: #1a237e;
            letter-spacing: 1px;
            display: flex;
            align-items: center;
        }
        .alarm-stat-row {
            display: flex;
            justify-content: space-around;
            align-items: flex-end;
            margin-top: 18px;
            margin-bottom: 6px;
            gap: 12px;
        }
        .alarm-stat-item {
            flex: 1;
            background: #fff;
            border-radius: 10px;
            box-shadow: 0 1px 4px 0 rgba(21,101,192,0.04);
            padding: 18px 0 10px 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            min-width: 90px;
        }
        .alarm-stat-label {
            font-size: 15px;
            color: #607d8b;
            margin-bottom: 8px;
        }
        .alarm-stat-num {
            font-size: 36px;
            font-weight: bold;
            letter-spacing: 2px;
            line-height: 1.1;
            margin-bottom: 2px;
            transition: color 0.3s;
        }
        .alarm-total {
            color: #1a237e;
            text-shadow: 0 2px 8px #e3f2fd;
        }
        .alarm-unhandled {
            color: #C62828;
            text-shadow: 0 2px 8px #ffcdd2;
        }
        .alarm-handled {
            color: #2E7D32;
            text-shadow: 0 2px 8px #c8e6c9;
        }
        @media (max-width: 700px) {
            .alarm-stat-row {
                flex-direction: column;
                gap: 10px;
            }
            .alarm-stat-item {
                min-width: 0;
                width: 100%;
            }
        }
        .chart-container {
            width: 100%;
            height: 260px;
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        .chart-full {
            width: 100%;
            height: 100%;
            min-height: 180px;
        }
        .el-button.center-text {
            display: flex !important;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            font-weight: bold;
            height: 28px;
            min-width: 80px;
            border-radius: 0;
            padding: 0 18px;
            line-height: 28px;
        }
        .alarm-section-card {
            border: 2px solid #F56C6C !important;
            background: #FEF0F0 !important;
        }
    </style>
</head>
<body>
    <div id="generator-room-monitor">
        <div class="container">
            <div class="title"><i class='bx bx-battery'></i> 发电机房监测</div>
            <el-tabs v-model="activeTab">
                <!-- 1. 机房列表 -->
                <el-tab-pane label="机房列表" name="list">
                    <el-table :data="rooms" border stripe size="small">
                        <el-table-column prop="name" label="机房名称" width="180"></el-table-column>
                        <el-table-column prop="temp" label="温度"></el-table-column>
                        <el-table-column prop="humidity" label="湿度"></el-table-column>
                        <el-table-column prop="noise" label="噪声"></el-table-column>
                        <el-table-column prop="waterLeak" label="是否有水浸">
                            <template slot-scope="scope">
                                <el-tag :type="scope.row.waterLeak ? 'danger' : 'success'" size="mini">{{scope.row.waterLeak ? '是' : '否'}}</el-tag>
                            </template>
                        </el-table-column>
                        <el-table-column prop="offline" label="是否有设备离线">
                            <template slot-scope="scope">
                                <el-tag :type="scope.row.offline ? 'danger' : 'success'" size="mini">{{scope.row.offline ? '是' : '否'}}</el-tag>
                            </template>
                        </el-table-column>
                        <el-table-column prop="alert" label="是否有告警">
                            <template slot-scope="scope">
                                <el-tag :type="scope.row.alert ? 'danger' : 'success'" size="mini">{{scope.row.alert ? '是' : '否'}}</el-tag>
                            </template>
                        </el-table-column>
                        <el-table-column label="操作" width="220">
                            <template slot-scope="scope">
                                <div style="display: flex; flex-direction: row; gap: 12px; justify-content: center; align-items: center; width: 100%;">
                                    <el-button size="mini" type="primary" class="center-text" @click="openBindDialog(scope.row)">绑定信息</el-button>
                                    <el-button size="mini" type="success" class="center-text" style="min-width: 100px;" @click="openPointDialog(scope.row)">机房点位配置</el-button>
                                </div>
                            </template>
                        </el-table-column>
                    </el-table>
                </el-tab-pane>
                <!-- 2. 综合仪表盘 -->
                <el-tab-pane label="综合仪表盘" name="dashboard">
                    <div style="margin-bottom:18px;display:flex;align-items:center;gap:18px;">
                        <el-select v-model="dashboardRoom" placeholder="请选择机房" style="width:220px;">
                            <el-option v-for="room in rooms" :key="room.name" :label="room.name" :value="room.name"></el-option>
                        </el-select>
                    </div>
                    <div class="dashboard-vertical">
                        <el-card class="dashboard-card alarm-stat-card" shadow="hover" style="margin-bottom:28px;">
                            <div slot="header" class="alarm-stat-title">
                                <i class="el-icon-warning-outline" style="color:#C62828;margin-right:8px;"></i>告警统计
                            </div>
                            <div class="alarm-stat-row">
                                <div class="alarm-stat-item">
                                    <div class="alarm-stat-label">所有告警</div>
                                    <div class="alarm-stat-num alarm-total" id="alarm-total">0</div>
                                </div>
                                <div class="alarm-stat-item">
                                    <div class="alarm-stat-label">未处理</div>
                                    <div class="alarm-stat-num alarm-unhandled" id="alarm-unhandled">0</div>
                                </div>
                                <div class="alarm-stat-item">
                                    <div class="alarm-stat-label">已处理</div>
                                    <div class="alarm-stat-num alarm-handled" id="alarm-handled">0</div>
                                </div>
                            </div>
                        </el-card>
                        <el-card class="dashboard-card" shadow="hover" style="margin-bottom:28px;">
                            <div slot="header" style="display:flex;align-items:center;justify-content:space-between;">
                                <span>油箱液位变化</span>
                                <el-select v-model="dashboardPeriod" size="mini" style="width:70px;">
                                    <el-option label="日" value="day"></el-option>
                                    <el-option label="周" value="week"></el-option>
                                    <el-option label="月" value="month"></el-option>
                                </el-select>
                            </div>
                            <div class="chart-container">
                                <div :id="'oil-chart'" class="chart-full"></div>
                            </div>
                        </el-card>
                        <el-card class="dashboard-card" shadow="hover">
                            <div slot="header" style="display:flex;align-items:center;justify-content:space-between;">
                                <span>发电机电池剩余电量变化</span>
                                <el-select v-model="dashboardPeriod" size="mini" style="width:70px;">
                                    <el-option label="日" value="day"></el-option>
                                    <el-option label="周" value="week"></el-option>
                                    <el-option label="月" value="month"></el-option>
                                </el-select>
                            </div>
                            <div class="chart-container">
                                <div :id="'battery-chart'" class="chart-full"></div>
                            </div>
                        </el-card>
                    </div>
                </el-tab-pane>
                <!-- 3. 设备详情监控 -->
                <el-tab-pane label="设备详情监控" name="device">
                    <el-select v-model="selectedRoom" placeholder="请选择机房" style="margin-bottom:16px;width:220px;">
                        <el-option v-for="room in rooms" :key="room.name" :label="room.name" :value="room.name"></el-option>
                    </el-select>
                    <el-card class="section" shadow="hover" style="margin-bottom:18px;">
                        <div slot="header">环境状态</div>
                        <el-table :data="filteredDevices.filter(d=>d.type==='环境')" border stripe class="device-table" size="small">
                            <el-table-column prop="name" label="设备名称" width="120"></el-table-column>
                            <el-table-column prop="waterLeak" label="水浸情况" width="100">
                                <template slot-scope="scope">
                                    <el-tag :type="scope.row.waterLeak===true?'danger':'success'" size="mini" style="font-weight: bold; font-size: 12px;">{{scope.row.waterLeak===true?'水浸':'非水浸'}}</el-tag>
                                </template>
                            </el-table-column>
                            <el-table-column prop="noise" label="室内噪音" width="120">
                                <template slot-scope="scope">
                                    <span :style="{color: '#000000', fontSize: '13px'}">
                                        {{scope.row.noise}}
                                    </span>
                                    <el-tag :type="getNoiseStatusColor(scope.row.noise)" size="mini" style="margin-left: 5px; font-weight: bold;">
                                        {{getNoiseStatusText(scope.row.noise)}}
                                    </el-tag>
                                </template>
                            </el-table-column>
                            <el-table-column prop="temp" label="室内温度" width="120">
                                <template slot-scope="scope">
                                    <span :style="{color: '#000000', fontSize: '13px'}">
                                        {{scope.row.temp}}
                                    </span>
                                    <el-tag 
                                        :type="getTempStatusColor(scope.row.temp)" 
                                        size="mini" 
                                        :style="getTempStatusColor(scope.row.temp) === 'warning' ? 'margin-left: 5px; font-weight: bold; background-color: #FF8F00; border-color: #FF8F00; color: white;' : 'margin-left: 5px; font-weight: bold;'">
                                        {{getTempStatusText(scope.row.temp)}}
                                    </el-tag>
                                </template>
                            </el-table-column>
                            <el-table-column prop="humidity" label="室内湿度" width="120">
                                <template slot-scope="scope">
                                    <span :style="{color: '#000000', fontSize: '13px'}">
                                        {{scope.row.humidity}}
                                    </span>
                                    <el-tag 
                                        :type="getHumidityStatusColor(scope.row.humidity)" 
                                        size="mini" 
                                        :style="getHumidityStatusColor(scope.row.humidity) === 'warning' ? 'margin-left: 5px; font-weight: bold; background-color: #FF8F00; border-color: #FF8F00; color: white;' : getHumidityStatusColor(scope.row.humidity) === 'danger' ? 'margin-left: 5px; font-weight: bold; background-color: #B71C1C; border-color: #B71C1C; color: white;' : 'margin-left: 5px; font-weight: bold;'">
                                        {{getHumidityStatusText(scope.row.humidity)}}
                                    </el-tag>
                                </template>
                            </el-table-column>
                        </el-table>
                    </el-card>
                    <el-card class="section" shadow="hover" style="margin-bottom:18px;">
                        <div slot="header">发电机运行状态</div>
                        <el-table :data="filteredDevices.filter(d=>d.type==='发电机')" border stripe class="device-table" size="small">
                            <el-table-column prop="name" label="发电机名称" width="120"></el-table-column>
                            <el-table-column prop="voltage" label="发电机电压"></el-table-column>
                            <el-table-column prop="current" label="发电机电流"></el-table-column>
                            <el-table-column prop="frequency" label="发电机频率"></el-table-column>
                            <el-table-column prop="rpm" label="发电机转速"></el-table-column>
                            <el-table-column label="远程控制" width="120">
                                <template slot-scope="scope">
                                    <el-button size="mini" type="primary">启停按钮</el-button>
                                </template>
                            </el-table-column>
                        </el-table>
                    </el-card>
                    <el-card class="section" shadow="hover" style="margin-bottom:18px;">
                        <div slot="header">发电机电池状态</div>
                        <el-table :data="filteredDevices.filter(d=>d.type==='电池')" border stripe class="device-table" size="small">
                            <el-table-column prop="name" label="电池名称" width="120"></el-table-column>
                            <el-table-column prop="chargeVoltage" label="充电电压"></el-table-column>
                            <el-table-column prop="chargeCurrent" label="充电电流"></el-table-column>
                            <el-table-column prop="batteryLevel" label="电池剩余电量"></el-table-column>
                        </el-table>
                    </el-card>
                    <el-card class="section" shadow="hover" style="margin-bottom:18px;">
                        <div slot="header">油箱液位</div>
                        <el-table :data="filteredDevices.filter(d=>d.type==='油箱')" border stripe class="device-table" size="small">
                            <el-table-column prop="name" label="油箱名称" width="120"></el-table-column>
                            <el-table-column prop="oilLevel" label="油液位" width="500">
                                <template slot-scope="scope">
                                    <div style="display: flex; align-items: center; gap: 15px;">
                                        <!-- 下拉列表 -->
                                        <el-select 
                                            v-model="scope.row.oilLevelInput" 
                                            placeholder="选择液位值" 
                                            size="small" 
                                            style="width: 100px;"
                                            @change="updateOilLevelFromSelect(scope.row)">
                                            <el-option 
                                                v-for="value in oilLevelOptions" 
                                                :key="value" 
                                                :label="value + '米'" 
                                                :value="value.toString()">
                                            </el-option>
                                        </el-select>

                                        <div style="flex: 1; position: relative;">
                                            <span style="font-weight: bold; color: #303133; min-width: 60px;">
                                                {{getOilLevelValue(scope.row.oilLevel)}}米
                                            </span>
                                            <div style="flex: 1; position: relative;">
                                                <!-- 进度条背景 -->
                                                <div style="width: 100%; height: 20px; background: #E4E7ED; border-radius: 10px; position: relative; overflow: hidden;">
                                                    <!-- 动态进度条 -->
                                                    <div :style="{
                                                        width: getOilLevelPercentage(scope.row.oilLevel) + '%',
                                                        height: '100%',
                                                        background: getOilLevelStatusColor(scope.row.oilLevel, scope.row.name) === 'danger' ? '#F56C6C' : 
                                                                   getOilLevelStatusColor(scope.row.oilLevel, scope.row.name) === 'warning' ? '#E6A23C' : 
                                                                   getOilLevelStatusColor(scope.row.oilLevel, scope.row.name) === 'success' ? '#67C23A' : '#909399',
                                                        borderRadius: '10px',
                                                        transition: 'width 0.3s ease'
                                                    }"></div>
                                                </div>
                                                <!-- 指示器箭头 -->
                                                <div :style="{
                                                    position: 'absolute',
                                                    top: '-5px',
                                                    left: getOilLevelPercentage(scope.row.oilLevel) + '%',
                                                    transform: 'translateX(-50%)',
                                                    width: '0',
                                                    height: '0',
                                                    borderLeft: '8px solid transparent',
                                                    borderRight: '8px solid transparent',
                                                    borderTop: '12px solid #303133',
                                                    zIndex: '10'
                                                }"></div>
                                                <!-- 当前值标签 -->
                                                <div :style="{
                                                    position: 'absolute',
                                                    top: '-30px',
                                                    left: getOilLevelPercentage(scope.row.oilLevel) + '%',
                                                    transform: 'translateX(-50%)',
                                                    background: '#303133',
                                                    color: 'white',
                                                    padding: '2px 6px',
                                                    borderRadius: '4px',
                                                    fontSize: '12px',
                                                    whiteSpace: 'nowrap',
                                                    zIndex: '10'
                                                }">
                                                    {{getOilLevelValue(scope.row.oilLevel)}}米
                                                </div>
                                                <!-- 刻度标记 -->
                                                <div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 11px; color: #606266;">
                                                    <span>0米</span>
                                                    <span>2米</span>
                                                    <span>4米</span>
                                                    <span>6米</span>
                                                    <span>8米</span>
                                                    <span>10米</span>
                                                </div>
                                                <!-- 状态标签 -->
                                                <div style="display: flex; justify-content: center; margin-top: 2px; font-size: 10px;">
                                                    <span :style="{
                                                        background: getOilLevelStatusColor(scope.row.oilLevel, scope.row.name) === 'danger' ? '#F56C6C' : 
                                                                   getOilLevelStatusColor(scope.row.oilLevel, scope.row.name) === 'warning' ? '#E6A23C' : 
                                                                   getOilLevelStatusColor(scope.row.oilLevel, scope.row.name) === 'success' ? '#67C23A' : '#909399',
                                                        color: 'white',
                                                        padding: '2px 6px',
                                                        borderRadius: '4px',
                                                        fontWeight: 'bold'
                                                    }">
                                                        {{getOilLevelStatusText(scope.row.oilLevel, scope.row.name)}}
                                                    </span>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </template>
                            </el-table-column>
                        </el-table>
                    </el-card>
                    <el-card class="section alarm-section-card" shadow="hover" style="margin-bottom:0; border:2px solid #F56C6C; background:#FEF0F0;">
                        <div slot="header" style="color:#C62828; font-weight:bold; display:flex; align-items:center;"><i class="el-icon-warning-outline" style="margin-right:8px;"></i>告警列表</div>
                        <el-table :data="filteredAlerts.filter(a=>a.status==='未处理')" border stripe class="alert-table" size="small" @row-dblclick="handleAlertDoubleClick" style="cursor: pointer;">
                            <el-table-column prop="device" label="设备"></el-table-column>
                            <el-table-column prop="type" label="告警类型"></el-table-column>
                            <el-table-column prop="status" label="状态">
                                <template slot-scope="scope">
                                    <el-tag :type="scope.row.status==='未处理'?'danger':'success'" size="mini">{{scope.row.status}}</el-tag>
                                </template>
                            </el-table-column>
                            <el-table-column prop="time" label="时间"></el-table-column>
                            <el-table-column label="操作提示" width="100">
                                <template slot-scope="scope">
                                    <el-tag type="info" size="mini">双击处理</el-tag>
                                </template>
                            </el-table-column>
                        </el-table>
                    </el-card>
                </el-tab-pane>
                <!-- 4. 机房点位图 -->
                <el-tab-pane label="机房点位图" name="map">
                    <el-select v-model="selectedRoom" placeholder="请选择机房" style="margin-bottom:16px;width:220px;">
                        <el-option v-for="room in rooms" :key="room.name" :label="room.name" :value="room.name"></el-option>
                    </el-select>
                    <el-card class="section" shadow="hover">
                        <div slot="header">机房点位图</div>
                        <div class="point-map">
                            <span v-if="!pointMarkers[selectedRoom]">暂无背景图和点位信息</span>
                            <template v-else>
                                <span style="color:#1565C0;">[背景图占位]</span>
                                <div v-for="(marker, idx) in pointMarkers[selectedRoom]" :key="idx" class="point-marker" :style="{left: marker.x+'%', top: marker.y+'%'}" :title="marker.device" @click="selectDevice(marker)">
                                    <div style="position:absolute;top:-28px;left:50%;transform:translateX(-50%);font-size:13px;font-weight:bold;color:#333;white-space:nowrap;">{{marker.device}}</div>
                                    <i :class="deviceImages[marker.device]" style="font-size:28px;"></i>
                                    <div style="position:absolute;bottom:-32px;left:50%;transform:translateX(-50%);display:flex;gap:4px;">
                                        <el-tag v-if="getDeviceAlertStatus(marker.device)" type="danger" size="mini">告警</el-tag>
                                        <el-tag v-else type="success" size="mini">正常</el-tag>
                                        <el-tag v-if="getDeviceOfflineStatus(marker.device)" type="danger" size="mini">离线</el-tag>
                                        <el-tag v-else type="success" size="mini">在线</el-tag>
                                    </div>
                                </div>
                            </template>
                        </div>
                        <div v-if="selectedDevice" class="device-detail-panel">
                            <el-card shadow="never" style="margin-top:18px;">
                                <div slot="header">{{selectedDevice.device}} 详情</div>
                                <template v-if="selectedDeviceType==='发电机'">
                                    <el-table :data="getDeviceData(selectedDevice.device)" border stripe size="small">
                                        <el-table-column prop="name" label="发电机名称" width="120"></el-table-column>
                                        <el-table-column prop="voltage" label="发电机电压"></el-table-column>
                                        <el-table-column prop="current" label="发电机电流"></el-table-column>
                                        <el-table-column prop="frequency" label="发电机频率"></el-table-column>
                                        <el-table-column prop="rpm" label="发电机转速"></el-table-column>
                                    </el-table>
                                </template>
                                <template v-else-if="selectedDeviceType==='电池'">
                                    <el-table :data="getDeviceData(selectedDevice.device)" border stripe size="small">
                                        <el-table-column prop="name" label="电池名称" width="120"></el-table-column>
                                        <el-table-column prop="chargeVoltage" label="充电电压"></el-table-column>
                                        <el-table-column prop="chargeCurrent" label="充电电流"></el-table-column>
                                        <el-table-column prop="batteryLevel" label="电池剩余电量"></el-table-column>
                                    </el-table>
                                </template>
                                <template v-else-if="selectedDeviceType==='环境'">
                                    <el-table :data="getDeviceData(selectedDevice.device)" border stripe size="small">
                                        <el-table-column prop="name" label="设备名称" width="120"></el-table-column>
                                        <el-table-column prop="waterLeak" label="水浸情况"></el-table-column>
                                        <el-table-column prop="noise" label="室内噪音"></el-table-column>
                                        <el-table-column prop="temp" label="室内温度"></el-table-column>
                                        <el-table-column prop="humidity" label="室内湿度"></el-table-column>
                                    </el-table>
                                </template>
                                <template v-else-if="selectedDeviceType==='油箱'">
                                    <el-table :data="getDeviceData(selectedDevice.device)" border stripe size="small">
                                        <el-table-column prop="name" label="油箱名称" width="120"></el-table-column>
                                        <el-table-column prop="oilLevel" label="油液位"></el-table-column>
                                    </el-table>
                                </template>
                                <div style="margin-top:10px;">
                                    <b>告警列表</b>
                                    <el-table :data="getDeviceAlerts(selectedDevice.device)" border stripe size="mini" style="margin-top:6px;">
                                        <el-table-column prop="type" label="告警类型"></el-table-column>
                                        <el-table-column prop="status" label="状态"></el-table-column>
                                        <el-table-column prop="time" label="时间"></el-table-column>
                                    </el-table>
                                </div>
                            </el-card>
                        </div>
                    </el-card>
                </el-tab-pane>
            </el-tabs>
        </div>
        <!-- 机房绑定弹窗 -->
        <el-dialog :visible.sync="bindDialogVisible" title="机房绑定设备" width="800px" append-to-body>
            <el-form :model="bindForm" label-width="140px" size="small">
                <el-form-item label="机房名称">
                    <el-input v-model="bindForm.name" disabled></el-input>
                </el-form-item>
                <el-form-item label="绑定发电机设备">
                    <el-select v-model="bindForm.generators" multiple placeholder="请选择发电机设备">
                        <el-option v-for="item in allGenerators" :key="item" :label="item" :value="item"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="绑定发电机电池">
                    <el-select v-model="bindForm.batteries" multiple placeholder="请选择发电机电池">
                        <el-option v-for="item in allBatteries" :key="item" :label="item" :value="item"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="绑定环境信息">
                    <el-select v-model="bindForm.envDevice" placeholder="请选择环境监测设备" style="width: 100%; margin-bottom: 15px;">
                        <el-option v-for="item in availableEnvDevices" :key="item.id" :label="item.name" :value="item.id"></el-option>
                    </el-select>
                    
                    <div v-if="bindForm.envDevice" style="border: 1px solid #EBEEF5; border-radius: 4px; padding: 15px; background: #FAFAFA;">
                        <div style="font-weight: bold; color: #303133; margin-bottom: 15px;">环境监测设备配置</div>
                        
                        <!-- 水浸配置 -->
                        <el-form-item label="水浸监测" label-width="100px" size="small">
                            <div style="display: flex; align-items: center; gap: 10px;">
                                <span style="font-size: 12px; color: #606266;">水浸状态：</span>
                                <el-tag type="danger" size="mini">水浸 - 红色</el-tag>
                                <el-tag type="success" size="mini">非水浸 - 绿色</el-tag>
                            </div>
                        </el-form-item>
                        
                        <!-- 噪声配置 -->
                        <el-form-item label="噪声监测" label-width="100px" size="small">
                            <el-row :gutter="12">
                                <el-col :span="12">
                                    <el-form-item label="预警阈值" label-width="80px" size="small">
                                        <el-input v-model="bindForm.envConfig.noiseWarning" placeholder="如：50" style="width: 100%;">
                                            <template slot="append">dB</template>
                                        </el-input>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12">
                                    <el-form-item label="告警阈值" label-width="80px" size="small">
                                        <el-input v-model="bindForm.envConfig.noiseDanger" placeholder="如：70" style="width: 100%;">
                                            <template slot="append">dB</template>
                                        </el-input>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <div style="display: flex; align-items: center; gap: 10px; margin-top: 5px;">
                                <span style="font-size: 12px; color: #606266;">显示规则：</span>
                                <el-tag type="success" size="mini">正常 - 绿色</el-tag>
                                <el-tag type="warning" size="mini">预警 - 黄色</el-tag>
                                <el-tag type="danger" size="mini">告警 - 红色</el-tag>
                            </div>
                        </el-form-item>
                        
                        <!-- 温度配置 -->
                        <el-form-item label="温度监测" label-width="100px" size="small">
                            <el-row :gutter="12">
                                <el-col :span="12">
                                    <el-form-item label="预警阈值" label-width="80px" size="small">
                                        <el-input v-model="bindForm.envConfig.tempWarning" placeholder="如：35" style="width: 100%;">
                                            <template slot="append">℃</template>
                                        </el-input>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12">
                                    <el-form-item label="告警阈值" label-width="80px" size="small">
                                        <el-input v-model="bindForm.envConfig.tempDanger" placeholder="如：45" style="width: 100%;">
                                            <template slot="append">℃</template>
                                        </el-input>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <div style="display: flex; align-items: center; gap: 10px; margin-top: 5px;">
                                <span style="font-size: 12px; color: #606266;">显示规则：</span>
                                <el-tag type="success" size="mini">正常 - 绿色</el-tag>
                                <el-tag type="warning" size="mini">预警 - 黄色</el-tag>
                                <el-tag type="danger" size="mini">告警 - 红色</el-tag>
                            </div>
                        </el-form-item>
                        
                        <!-- 湿度配置 -->
                        <el-form-item label="湿度监测" label-width="100px" size="small">
                            <el-row :gutter="12">
                                <el-col :span="12">
                                    <el-form-item label="预警阈值" label-width="80px" size="small">
                                        <el-input v-model="bindForm.envConfig.humidityWarning" placeholder="如：75" style="width: 100%;">
                                            <template slot="append">%</template>
                                        </el-input>
                                    </el-form-item>
                                </el-col>
                                <el-col :span="12">
                                    <el-form-item label="告警阈值" label-width="80px" size="small">
                                        <el-input v-model="bindForm.envConfig.humidityDanger" placeholder="如：80" style="width: 100%;">
                                            <template slot="append">%</template>
                                        </el-input>
                                    </el-form-item>
                                </el-col>
                            </el-row>
                            <div style="display: flex; align-items: center; gap: 10px; margin-top: 5px;">
                                <span style="font-size: 12px; color: #606266;">显示规则：</span>
                                <el-tag type="success" size="mini">正常 - 绿色</el-tag>
                                <el-tag type="warning" size="mini">预警 - 黄色</el-tag>
                                <el-tag type="danger" size="mini">告警 - 红色</el-tag>
                            </div>
                        </el-form-item>
                    </div>
                </el-form-item>
                <el-form-item label="绑定发电机油箱">
                    <div style="margin-bottom: 10px;">
                        <el-button size="mini" type="primary" @click="showTankDeviceSelector">
                            <i class="el-icon-plus"></i> 添加油箱设备
                        </el-button>
                    </div>
                    <div v-for="(device, index) in bindForm.tankDevices" :key="index" style="border: 1px solid #EBEEF5; border-radius: 4px; padding: 12px; margin-bottom: 10px; background: #FAFAFA;">
                        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
                            <span style="font-weight: bold; color: #303133;">{{device.name}}</span>
                            <el-button size="mini" type="danger" @click="removeTankDevice(index)">
                                <i class="el-icon-delete"></i> 删除
                            </el-button>
                        </div>
                        <el-row :gutter="12">
                            <el-col :span="12">
                                <el-form-item label="有效范围最小值" label-width="120px" size="small">
                                    <el-input v-model="device.minValue" placeholder="如：0" style="width: 100%;" @input="onTankRangeChange(index)">
                                        <template slot="append">米</template>
                                    </el-input>
                                </el-form-item>
                            </el-col>
                            <el-col :span="12">
                                <el-form-item label="有效范围最大值" label-width="120px" size="small">
                                    <el-input v-model="device.maxValue" placeholder="如：10" style="width: 100%;" @input="onTankRangeChange(index)">
                                        <template slot="append">米</template>
                                    </el-input>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row :gutter="12">
                            <el-col :span="16">
                                <el-form-item label="操作" label-width="50px" size="small">
                                    <el-button 
                                        v-if="device.showRefreshButton" 
                                        type="primary" 
                                        size="small" 
                                        @click="refreshTankEffectiveRange(index)"
                                        style="margin-top: 8px;">
                                        刷新有效范围
                                    </el-button>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row :gutter="12">
                            <el-col :span="24">
                                <el-form-item label="预警范围显示" label-width="100px" size="small">
                                    <div style="display: flex; flex-direction: column; gap: 8px;">
                                        <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
                                            <span style="font-size: 12px; color: #606266; min-width: 50px;">超低:</span>
                                            <span style="font-size: 12px; color: #303133;">{{device.warningRanges ? device.warningRanges.ultraLow : "0 - 2"}} {{device.unit}}</span>
                                            <span style="font-size: 12px; color: #F56C6C;">红色</span>
                                        </div>
                                        <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
                                            <span style="font-size: 12px; color: #606266; min-width: 50px;">低:</span>
                                            <span style="font-size: 12px; color: #303133;">{{device.warningRanges ? device.warningRanges.low : "2 - 4"}} {{device.unit}}</span>
                                            <span style="font-size: 12px; color: #E6A23C;">黄色</span>
                                        </div>
                                        <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
                                            <span style="font-size: 12px; color: #606266; min-width: 50px;">正常:</span>
                                            <span style="font-size: 12px; color: #303133;">{{device.warningRanges ? device.warningRanges.normal : "4 - 6"}} {{device.unit}}</span>
                                            <span style="font-size: 12px; color: #67C23A;">绿色</span>
                                        </div>
                                        <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
                                            <span style="font-size: 12px; color: #606266; min-width: 50px;">高:</span>
                                            <span style="font-size: 12px; color: #303133;">{{device.warningRanges ? device.warningRanges.high : "6 - 8"}} {{device.unit}}</span>
                                            <span style="font-size: 12px; color: #E6A23C;">黄色</span>
                                        </div>
                                        <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
                                            <span style="font-size: 12px; color: #606266; min-width: 50px;">超高:</span>
                                            <span style="font-size: 12px; color: #303133;">{{device.warningRanges ? device.warningRanges.ultraHigh : "8 - 10"}} {{device.unit}}</span>
                                            <span style="font-size: 12px; color: #F56C6C;">红色</span>
                                        </div>
                                    </div>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row :gutter="12">
                            <el-col :span="24">
                                <el-form-item label="预警值配置" label-width="100px" size="small">
                                    <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;">
                                        <input type="text" :id="'tankWarningValue1_' + index" placeholder="值1" value="0" readonly style="width: 80px; height: 28px; padding: 0 8px; border: 1px solid #DCDFE6; border-radius: 4px; font-size: 12px; background-color: #F5F7FA;">
                                        <span style="font-size: 12px; color: #606266;">{{device.unit}}</span>
                                        <input type="text" :id="'tankWarningValue2_' + index" placeholder="值2" style="width: 80px; height: 28px; padding: 0 8px; border: 1px solid #DCDFE6; border-radius: 4px; font-size: 12px;" @input="onTankWarningValueInput(index)">
                                        <span style="font-size: 12px; color: #606266;">{{device.unit}}</span>
                                        <input type="text" :id="'tankWarningValue3_' + index" placeholder="值3" style="width: 80px; height: 28px; padding: 0 8px; border: 1px solid #DCDFE6; border-radius: 4px; font-size: 12px;" @input="onTankWarningValueInput(index)">
                                        <span style="font-size: 12px; color: #606266;">{{device.unit}}</span>
                                        <input type="text" :id="'tankWarningValue4_' + index" placeholder="值4" style="width: 80px; height: 28px; padding: 0 8px; border: 1px solid #DCDFE6; border-radius: 4px; font-size: 12px;" @input="onTankWarningValueInput(index)">
                                        <span style="font-size: 12px; color: #606266;">{{device.unit}}</span>
                                        <input type="text" :id="'tankWarningValue5_' + index" placeholder="值5" style="width: 80px; height: 28px; padding: 0 8px; border: 1px solid #DCDFE6; border-radius: 4px; font-size: 12px;" @input="onTankWarningValueInput(index)">
                                        <span style="font-size: 12px; color: #606266;">{{device.unit}}</span>
                                        <input type="text" :id="'tankWarningValue6_' + index" placeholder="值6" value="10" readonly style="width: 80px; height: 28px; padding: 0 8px; border: 1px solid #DCDFE6; border-radius: 4px; font-size: 12px; background-color: #F5F7FA;">
                                        <span style="font-size: 12px; color: #606266;">{{device.unit}}</span>
                                    </div>
                                    <el-button 
                                        v-if="device.showWarningRefreshButton" 
                                        type="success" 
                                        size="small" 
                                        @click="refreshTankWarningRanges(index)"
                                        style="margin-top: 8px;">
                                        刷新预警范围
                                    </el-button>
                                </el-form-item>
                            </el-col>
                        </el-row>
                    </div>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="bindDialogVisible=false">取 消</el-button>
                <el-button type="primary" @click="saveBindInfo">确 定</el-button>
            </div>
        </el-dialog>
        <!-- 电池绑定弹窗 -->
        <el-dialog :visible.sync="batteryBindDialogVisible" title="机房绑定发电机电池" width="600px" append-to-body>
            <el-form :model="batteryBindForm" label-width="140px" size="small">
                <el-form-item label="机房名称">
                    <el-input v-model="batteryBindForm.name" disabled></el-input>
                </el-form-item>
                <el-form-item label="绑定发电机电池">
                    <el-select v-model="batteryBindForm.batteries" multiple placeholder="请选择发电机电池">
                        <el-option v-for="item in allBatteries" :key="item" :label="item" :value="item"></el-option>
                    </el-select>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="batteryBindDialogVisible=false">取 消</el-button>
                <el-button type="primary" @click="saveBatteryBindInfo">确 定</el-button>
            </div>
        </el-dialog>
        <!-- 环境绑定弹窗 -->
        <el-dialog :visible.sync="envBindDialogVisible" title="机房绑定环境信息" width="600px" append-to-body>
            <el-form :model="envBindForm" label-width="140px" size="small">
                <el-form-item label="机房名称">
                    <el-input v-model="envBindForm.name" disabled></el-input>
                </el-form-item>
                <el-form-item label="绑定环境信息">
                    <el-select v-model="envBindForm.envs" multiple filterable placeholder="请选择环境传感器">
                        <el-option v-for="item in allSensors" :key="item" :label="item" :value="item"></el-option>
                    </el-select>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="envBindDialogVisible=false">取 消</el-button>
                <el-button type="primary" @click="saveEnvBindInfo">确 定</el-button>
            </div>
        </el-dialog>
        <!-- 点位配置弹窗 -->
        <el-dialog :visible.sync="pointDialogVisible" title="机房点位配置" width="700px" append-to-body>
            <el-form label-width="120px" size="small">
                <el-form-item label="背景设置">
                    <el-radio-group v-model="pointBgMode">
                        <el-radio label="image">上传图片</el-radio>
                        <el-radio label="color">纯色背景</el-radio>
                    </el-radio-group>
                    <div v-if="pointBgMode==='image'" style="margin-top:8px;">
                        <el-upload class="upload-demo" drag action="#" :show-file-list="false" :on-change="handlePointBgUpload">
                            <i class="el-icon-upload"></i>
                            <div class="el-upload__text">将图片拖到此处，或<em>点击上传</em></div>
                        </el-upload>
                        <div v-if="pointBgUrl" style="margin-top:8px;"><img :src="pointBgUrl" style="max-width:100%;max-height:120px;border-radius:4px;"></div>
                    </div>
                    <div v-else style="margin-top:8px;">
                        <el-color-picker v-model="pointBgColor"></el-color-picker>
                        <span style="margin-left:12px;">当前颜色：<span :style="{background:pointBgColor,display:'inline-block',width:'32px',height:'16px',borderRadius:'4px',border:'1px solid #eee'}"></span></span>
                    </div>
                </el-form-item>
                <el-form-item label="设备点位配置">
                    <el-table :data="pointDevices" border size="mini">
                        <el-table-column label="设备" width="120">
                            <template slot-scope="scope">
                                <i :class="deviceImages[scope.row.name]" style="font-size:24px;color:#1565C0;margin-right:6px;vertical-align:middle;"></i>{{scope.row.name}}
                            </template>
                        </el-table-column>
                        <el-table-column label="类型" prop="type" width="80"></el-table-column>
                        <el-table-column label="X坐标" width="90">
                            <template slot-scope="scope">
                                <el-input v-model="scope.row.x" size="mini" placeholder="X"></el-input>
                            </template>
                        </el-table-column>
                        <el-table-column label="Y坐标" width="90">
                            <template slot-scope="scope">
                                <el-input v-model="scope.row.y" size="mini" placeholder="Y"></el-input>
                            </template>
                        </el-table-column>
                    </el-table>
                </el-form-item>
                <el-form-item label="点位预览">
                    <div style="position:relative;width:100%;height:220px;border-radius:8px;overflow:hidden;border:1px solid #ebeef5;background:#f5f7fa;">
                        <img v-if="pointBgMode==='image' && pointBgUrl" :src="pointBgUrl" style="width:100%;height:100%;object-fit:cover;position:absolute;left:0;top:0;z-index:1;">
                        <div v-else :style="{background:pointBgColor,width:'100%',height:'100%',position:'absolute',left:0,top:0,zIndex:1}"></div>
                        <div v-for="dev in pointDevices" :key="dev.name" :style="{position:'absolute',left:dev.x+'%',top:dev.y+'%',zIndex:2,transform:'translate(-50%,-50%)'}">
                            <i :class="deviceImages[dev.name]" style="font-size:36px;color:#1565C0;"></i>
                            <div style="text-align:center;font-size:12px;color:#333;">{{dev.name}}</div>
                        </div>
                    </div>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="pointDialogVisible=false">取 消</el-button>
                <el-button type="primary" @click="savePointInfo">确 定</el-button>
            </div>
        </el-dialog>
    </div>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
    <script>
        new Vue({
            el: '#generator-room-monitor',
            data() {
                return {
                    activeTab: 'list',
                    selectedRoom: '',
                    rooms: [
                        { name: 'A栋发电机房', temp: '26℃', humidity: '55%', noise: '50dB', waterLeak: false, offline: false, alert: true },
                        { name: 'B栋发电机房', temp: '27℃', humidity: '53%', noise: '52dB', waterLeak: true, offline: true, alert: false }
                    ],
                    devices: [
                        { room: 'A栋发电机房', name: '发电机1', type: '发电机', voltage: '400V', current: '120A', frequency: '50Hz', rpm: '1500', status: '运行', },
                        { room: 'A栋发电机房', name: '发电机电池1', type: '电池', chargeVoltage: '54V', chargeCurrent: '10A', batteryLevel: '85%', },
                        { room: 'A栋发电机房', name: '环境', type: '环境', waterLeak: false, noise: '50dB', temp: '26℃', humidity: '55%' },
                        { room: 'A栋发电机房', name: '油箱', type: '油箱', oilLevel: '70%', oilLevelInput: '7' },
                        { room: 'B栋发电机房', name: '发电机1', type: '发电机', voltage: '398V', current: '118A', frequency: '50Hz', rpm: '1490', status: '待机', },
                        { room: 'B栋发电机房', name: '发电机电池1', type: '电池', chargeVoltage: '53V', chargeCurrent: '9A', batteryLevel: '80%', },
                        { room: 'B栋发电机房', name: '环境', type: '环境', waterLeak: true, noise: '52dB', temp: '27℃', humidity: '53%' },
                        { room: 'B栋发电机房', name: '油箱', type: '油箱', oilLevel: '60%', oilLevelInput: '6' },
                    ],
                    alerts: [
                        { room: 'A栋发电机房', device: '发电机1', type: '过载', status: '未处理', time: '2024-06-01 10:30' },
                        { room: 'A栋发电机房', device: '发电机电池1', type: '电池电量低', status: '未处理', time: '2024-05-30 09:10' },
                        { room: 'B栋发电机房', device: '发电机1', type: '过载', status: '未处理', time: '2024-06-01 11:00' },
                        { room: 'A栋发电机房', device: '环境', type: '温度过高', status: '未处理', time: '2024-06-02 09:30' },
                        { room: 'B栋发电机房', device: '环境', type: '湿度异常', status: '未处理', time: '2024-06-02 10:10' }
                    ],
                    pointMarkers: {
                        'A栋发电机房': [
                            { device: '发电机1', type: '发电机', x: 20, y: 60 },
                            { device: '发电机电池1', type: '电池', x: 60, y: 30 },
                            { device: '油箱', type: '油箱', x: 80, y: 80 },
                            { device: '环境', type: '环境', x: 40, y: 50 }
                        ],
                        'B栋发电机房': [
                            { device: '发电机1', type: '发电机', x: 30, y: 50 },
                            { device: '发电机电池1', type: '电池', x: 70, y: 40 },
                            { device: '油箱', type: '油箱', x: 60, y: 80 },
                            { device: '环境', type: '环境', x: 50, y: 60 }
                        ]
                    },
                    bindDialogVisible: false,
                    bindForm: {
                        name: '',
                        generators: [],
                        batteries: [],
                        envDevice: null, // 新增环境设备ID
                        envConfig: { // 新增环境配置
                            noiseWarning: 50,
                            noiseDanger: 70,
                            tempWarning: 35,
                            tempDanger: 45,
                            humidityWarning: 75,
                            humidityDanger: 80,
                        },
                        tankDevices: [], // 新增油箱设备列表
                    },
                    allGenerators: ['发电机1', '发电机2'],
                    batteryBindDialogVisible: false,
                    batteryBindForm: {
                        name: '',
                        batteries: []
                    },
                    allBatteries: ['发电机电池1', '发电机电池2'],
                    envBindDialogVisible: false,
                    envBindForm: {
                        name: '',
                        envs: []
                    },
                    allSensors: ['水浸传感器A', '噪音传感器A', '温度传感器A', '湿度传感器A'],
                    pointDialogVisible: false,
                    pointBgMode: 'image',
                    pointBgUrl: '',
                    pointBgColor: '#f5f7fa',
                    pointDevices: [],
                    deviceImages: {
                        '发电机1': 'el-icon-cpu',
                        '发电机2': 'el-icon-cpu',
                        '发电机电池1': 'el-icon-battery-full',
                        '发电机电池2': 'el-icon-battery-full',
                        '油箱': 'el-icon-box',
                        '环境': 'el-icon-sunny',
                    },
                    dashboardRoom: '',
                    dashboardPeriod: 'day',
                    selectedDevice: null,
                    selectedDeviceType: '',
                    oilLevelOptions: Array.from({length: 11}, (_, i) => i), // 0-10米
                }
            },
            computed: {
                filteredDevices() {
                    if (!this.selectedRoom) return [];
                    return this.devices.filter(d => d.room === this.selectedRoom);
                },
                filteredAlerts() {
                    if (!this.selectedRoom) return [];
                    return this.alerts.filter(a => a.room === this.selectedRoom);
                },
                availableEnvDevices() { // 新增计算属性，获取可用的环境设备
                    return this.allSensors.map(name => ({
                        id: name,
                        name: name
                    }));
                }
            },
            watch: {
                activeTab(val) {
                    if (val === 'dashboard') {
                        this.$nextTick(() => {
                            this.initDashboard();
                        });
                    }
                },
                dashboardRoom() {
                    this.updateDashboardStats();
                    this.renderOilChart();
                    this.renderBatteryChart();
                },
                dashboardPeriod() {
                    this.renderOilChart();
                    this.renderBatteryChart();
                }
            },
            mounted() {
                this.dashboardRoom = this.rooms[0]?.name || '';
                this.selectedRoom = this.rooms[0]?.name || '';
                this.$nextTick(() => {
                    this.initDashboard();
                });
                this.animateDashboardNumbers();
            },
            methods: {
                openBindDialog(room) {
                    this.bindForm = {
                        name: room.name,
                        generators: [],
                        batteries: [],
                        envDevice: null, // 新增环境设备ID
                        envConfig: { // 新增环境配置
                            noiseWarning: 50,
                            noiseDanger: 70,
                            tempWarning: 35,
                            tempDanger: 45,
                            humidityWarning: 75,
                            humidityDanger: 80,
                        },
                        tankDevices: [], // 新增油箱设备列表
                    };
                    this.bindDialogVisible = true;
                },
                openBatteryBindDialog(room) {
                    this.batteryBindForm = {
                        name: room.name,
                        batteries: []
                    };
                    this.batteryBindDialogVisible = true;
                },
                openEnvBindDialog(room) {
                    this.envBindForm = {
                        name: room.name,
                        envs: []
                    };
                    this.envBindDialogVisible = true;
                },
                openPointDialog(room) {
                    this.pointDevices = [
                        { name: '发电机1', type: '发电机', x: 20, y: 60 },
                        { name: '发电机电池1', type: '电池', x: 60, y: 30 },
                        { name: '油箱', type: '油箱', x: 80, y: 80 },
                        { name: '环境', type: '环境', x: 40, y: 50 }
                    ];
                    this.pointBgMode = 'image';
                    this.pointBgUrl = '';
                    this.pointBgColor = '#f5f7fa';
                    this.pointDialogVisible = true;
                },
                saveBindInfo() {
                    this.$message.success('保存成功（演示）');
                    this.bindDialogVisible = false;
                },
                saveBatteryBindInfo() {
                    this.$message.success('保存成功（演示）');
                    this.batteryBindDialogVisible = false;
                },
                saveEnvBindInfo() {
                    this.$message.success('保存成功（演示）');
                    this.envBindDialogVisible = false;
                },
                handlePointBgUpload(file) {
                    const reader = new FileReader();
                    reader.onload = e => {
                        this.pointBgUrl = e.target.result;
                    };
                    reader.readAsDataURL(file.raw);
                },
                savePointInfo() {
                    this.$message.success('点位配置保存成功（演示）');
                    this.pointDialogVisible = false;
                },
                animateDashboardNumbers() {
                    const total = 5, unhandled = 2, handled = 3;
                    this.animateNum('alarm-total', total);
                    this.animateNum('alarm-unhandled', unhandled);
                    this.animateNum('alarm-handled', handled);
                },
                animateNum(id, target) {
                    const el = document.getElementById(id);
                    if (!el) return;
                    let n = 0;
                    const step = Math.max(1, Math.floor(target / 30));
                    const timer = setInterval(() => {
                        n += step;
                        if (n >= target) {
                            n = target;
                            clearInterval(timer);
                        }
                        el.textContent = n;
                    }, 30);
                },
                initDashboard() {
                    this.updateDashboardStats();
                    this.renderOilChart();
                    this.renderBatteryChart();
                },
                updateDashboardStats() {
                    const room = this.dashboardRoom;
                    const alerts = this.alerts.filter(a => a.room === room);
                    const total = alerts.length;
                    const unhandled = alerts.filter(a => a.status === '未处理').length;
                    const handled = alerts.filter(a => a.status === '已处理').length;
                    this.animateNum('alarm-total', total);
                    this.animateNum('alarm-unhandled', unhandled);
                    this.animateNum('alarm-handled', handled);
                },
                renderOilChart() {
                    const chart = echarts.init(document.getElementById('oil-chart'));
                    const hours = Array.from({length: 24}, (_, i) => i+1+':00');
                    const data = Array.from({length: 24}, () => Math.round(60+Math.random()*30));
                    chart.resize();
                    chart.setOption({
                        xAxis: { type: 'category', data: hours, boundaryGap: false },
                        yAxis: { type: 'value', min: 0, max: 120 },
                        series: [{
                            data,
                            type: 'line',
                            smooth: true,
                            areaStyle: { color: '#90caf9' },
                            lineStyle: { color: '#1565C0', width: 2 },
                            symbol: 'circle',
                            symbolSize: 6
                        }],
                        tooltip: { trigger: 'axis' },
                        grid: { left: 40, right: 20, top: 30, bottom: 30 },
                        title: { text: '', left: 'center', top: 0, textStyle: { fontSize: 14 } }
                    });
                },
                renderBatteryChart() {
                    const chart = echarts.init(document.getElementById('battery-chart'));
                    const hours = Array.from({length: 24}, (_, i) => i+1+':00');
                    const data = Array.from({length: 24}, () => Math.round(60+Math.random()*30));
                    chart.resize();
                    chart.setOption({
                        xAxis: { type: 'category', data: hours, boundaryGap: false },
                        yAxis: { type: 'value', min: 0, max: 120 },
                        series: [{
                            data,
                            type: 'line',
                            smooth: true,
                            areaStyle: { color: '#ffe082' },
                            lineStyle: { color: '#fbc02d', width: 2 },
                            symbol: 'circle',
                            symbolSize: 6
                        }],
                        tooltip: { trigger: 'axis' },
                        grid: { left: 40, right: 20, top: 30, bottom: 30 },
                        title: { text: '', left: 'center', top: 0, textStyle: { fontSize: 14 } }
                    });
                },
                selectDevice(marker) {
                    this.selectedDevice = marker;
                    this.selectedDeviceType = marker.type;
                },
                getDeviceData(name) {
                    return this.devices.filter(d => d.room === this.selectedRoom && d.name === name);
                },
                getDeviceAlerts(name) {
                    return this.alerts.filter(a => a.room === this.selectedRoom && a.device === name);
                },
                getDeviceAlertStatus(name) {
                    return this.alerts.some(a => a.room === this.selectedRoom && a.device === name && a.status === '未处理');
                },
                getDeviceOfflineStatus(name) {
                    const dev = this.devices.find(d => d.room === this.selectedRoom && d.name === name);
                    return dev && dev.offline === true;
                },
                showTankDeviceSelector() { // 新增方法，显示油箱设备选择器
                    const availableTankDevices = [
                        { id: 'tank1', name: '发电机油箱1', description: 'A栋发电机房主油箱' },
                        { id: 'tank2', name: '发电机油箱2', description: 'B栋发电机房主油箱' },
                        { id: 'tank3', name: '发电机油箱3', description: '备用油箱' }
                    ];
                    
                    window.availableTankDevicesList = availableTankDevices;
                    window.selectedTankDeviceIndex = undefined;
                    
                    window.selectTankDevice = (index) => {
                        window.selectedTankDeviceIndex = index;
                        // 重置所有设备的样式
                        document.querySelectorAll('.tank-device-item').forEach(el => {
                            el.style.backgroundColor = '#F5F7FA';
                            el.style.color = 'inherit';
                        });
                        // 高亮选中的设备
                        const selectedEl = document.querySelector(`.tank-device-item[data-index="${index}"]`);
                        if (selectedEl) {
                            selectedEl.style.backgroundColor = '#409EFF';
                            selectedEl.style.color = '#fff';
                        }
                    };
                    
                    const deviceList = availableTankDevices.map((device, index) => 
                        `<div class="tank-device-item" data-index="${index}" onclick="window.selectTankDevice(${index})" style="padding: 8px; border: 1px solid #DCDFE6; border-radius: 4px; margin-bottom: 8px; cursor: pointer; background: #F5F7FA;">
                            <div style="font-weight: bold; color: #303133;">${device.name}</div>
                            <div style="font-size: 12px; color: #606266; margin-top: 4px;">${device.description}</div>
                        </div>`
                    ).join('');
                    
                    this.$msgbox({
                        title: '选择油箱设备',
                        dangerouslyUseHTMLString: true,
                        message: `<p>请选择要添加的油箱设备：</p><div style="margin-top: 10px;">${deviceList}</div>`,
                        showCancelButton: true,
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        beforeClose: (action, instance, done) => {
                            if (action === 'confirm' && window.selectedTankDeviceIndex !== undefined) {
                                const selectedDevice = window.availableTankDevicesList[window.selectedTankDeviceIndex];
                                this.addTankDevice(selectedDevice);
                                window.selectedTankDeviceIndex = undefined;
                                window.availableTankDevicesList = undefined;
                                window.selectTankDevice = undefined;
                                done();
                            } else if (action === 'cancel') {
                                window.selectedTankDeviceIndex = undefined;
                                window.availableTankDevicesList = undefined;
                                window.selectTankDevice = undefined;
                                done();
                            } else {
                                this.$message.warning('请先选择一个设备');
                            }
                        }
                    });
                },
                addTankDevice(device) {
                    this.bindForm.tankDevices.push({
                        name: device.name,
                        minValue: '0',
                        maxValue: '10',
                        unit: '米',
                        warningRanges: {
                            ultraLow: '0 - 2',
                            low: '2 - 4',
                            normal: '4 - 6',
                            high: '6 - 8',
                            ultraHigh: '8 - 10'
                        },
                        showRefreshButton: false,
                        showWarningRefreshButton: false
                    });
                },
                removeTankDevice(index) { // 新增方法，移除油箱设备
                    this.$confirm(`确定要删除油箱设备 "${this.bindForm.tankDevices[index].name}" 吗？`, '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.bindForm.tankDevices.splice(index, 1);
                    }).catch(() => {
                        // 取消删除
                    });
                },
                onTankRangeChange(index) { // 新增方法，油箱有效范围变化时触发
                    const device = this.bindForm.tankDevices[index];
                    if (device.minValue && device.maxValue) {
                        this.$set(device, 'showRefreshButton', true);
                    } else {
                        this.$set(device, 'showRefreshButton', false);
                    }
                },
                onTankWarningValueInput(index) { // 新增方法，油箱预警值输入时触发
                    const device = this.bindForm.tankDevices[index];
                    const value2 = document.getElementById(`tankWarningValue2_${index}`).value;
                    const value3 = document.getElementById(`tankWarningValue3_${index}`).value;
                    const value4 = document.getElementById(`tankWarningValue4_${index}`).value;
                    const value5 = document.getElementById(`tankWarningValue5_${index}`).value;
                    
                    if (value2 && value3 && value4 && value5) {
                        this.$set(device, 'showWarningRefreshButton', true);
                    } else {
                        this.$set(device, 'showWarningRefreshButton', false);
                    }
                },
                refreshTankEffectiveRange(index) { // 新增方法，刷新油箱有效范围
                    const device = this.bindForm.tankDevices[index];
                    const minValue = parseFloat(device.minValue);
                    const maxValue = parseFloat(device.maxValue);
                    
                    if (isNaN(minValue) || isNaN(maxValue) || minValue >= maxValue) {
                        this.$message.error('请输入有效的范围值');
                        return;
                    }
                    
                    const range = maxValue - minValue;
                    const step = range / 5;
                    
                    device.warningRanges = {
                        ultraLow: `${minValue.toFixed(1)} - ${(minValue + step).toFixed(1)}`,
                        low: `${(minValue + step).toFixed(1)} - ${(minValue + step * 2).toFixed(1)}`,
                        normal: `${(minValue + step * 2).toFixed(1)} - ${(minValue + step * 3).toFixed(1)}`,
                        high: `${(minValue + step * 3).toFixed(1)} - ${(minValue + step * 4).toFixed(1)}`,
                        ultraHigh: `${(minValue + step * 4).toFixed(1)} - ${maxValue.toFixed(1)}`
                    };
                    
                    // 更新值1和值6的输入框
                    const value1Input = document.getElementById(`tankWarningValue1_${index}`);
                    const value6Input = document.getElementById(`tankWarningValue6_${index}`);
                    if (value1Input) value1Input.value = minValue.toFixed(1);
                    if (value6Input) value6Input.value = maxValue.toFixed(1);
                    
                    this.$set(device, 'showRefreshButton', false);
                    this.$message.success('有效范围已刷新，预警范围已更新');
                },
                refreshTankWarningRanges(index) { // 新增方法，刷新油箱预警范围
                    const device = this.bindForm.tankDevices[index];
                    const value1 = parseFloat(document.getElementById(`tankWarningValue1_${index}`).value);
                    const value2 = parseFloat(document.getElementById(`tankWarningValue2_${index}`).value);
                    const value3 = parseFloat(document.getElementById(`tankWarningValue3_${index}`).value);
                    const value4 = parseFloat(document.getElementById(`tankWarningValue4_${index}`).value);
                    const value5 = parseFloat(document.getElementById(`tankWarningValue5_${index}`).value);
                    const value6 = parseFloat(document.getElementById(`tankWarningValue6_${index}`).value);
                    
                    if (isNaN(value1) || isNaN(value2) || isNaN(value3) || isNaN(value4) || isNaN(value5) || isNaN(value6)) {
                        this.$message.error('请输入有效的数值');
                        return;
                    }
                    
                    if (value1 >= value2 || value2 >= value3 || value3 >= value4 || value4 >= value5 || value5 >= value6) {
                        this.$message.error('数值必须按照递增顺序排列');
                        return;
                    }
                    
                    device.warningRanges = {
                        ultraLow: `${value1.toFixed(1)} - ${value2.toFixed(1)}`,
                        low: `${value2.toFixed(1)} - ${value3.toFixed(1)}`,
                        normal: `${value3.toFixed(1)} - ${value4.toFixed(1)}`,
                        high: `${value4.toFixed(1)} - ${value5.toFixed(1)}`,
                        ultraHigh: `${value5.toFixed(1)} - ${value6.toFixed(1)}`
                    };
                    
                    this.$set(device, 'showWarningRefreshButton', false);
                    this.$message.success('数值符合标准，预警范围已更新');
                },
                getNoiseStatusColor(noise) {
                    if (parseFloat(noise) >= parseFloat(this.bindForm.envConfig.noiseDanger)) {
                        return 'danger';
                    } else if (parseFloat(noise) >= parseFloat(this.bindForm.envConfig.noiseWarning)) {
                        return 'warning';
                    }
                    return 'success';
                },
                getNoiseStatusText(noise) {
                    if (parseFloat(noise) >= parseFloat(this.bindForm.envConfig.noiseDanger)) {
                        return '告警';
                    } else if (parseFloat(noise) >= parseFloat(this.bindForm.envConfig.noiseWarning)) {
                        return '预警';
                    }
                    return '正常';
                },
                getTempStatusColor(temp) {
                    if (parseFloat(temp) >= parseFloat(this.bindForm.envConfig.tempDanger)) {
                        return 'danger';
                    } else if (parseFloat(temp) >= parseFloat(this.bindForm.envConfig.tempWarning)) {
                        return 'warning';
                    }
                    return 'success';
                },
                getTempStatusText(temp) {
                    if (parseFloat(temp) >= parseFloat(this.bindForm.envConfig.tempDanger)) {
                        return '告警';
                    } else if (parseFloat(temp) >= parseFloat(this.bindForm.envConfig.tempWarning)) {
                        return '预警';
                    }
                    return '正常';
                },
                getHumidityStatusColor(humidity) {
                    if (parseFloat(humidity) >= parseFloat(this.bindForm.envConfig.humidityDanger)) {
                        return 'danger';
                    } else if (parseFloat(humidity) >= parseFloat(this.bindForm.envConfig.humidityWarning)) {
                        return 'warning';
                    }
                    return 'success';
                },
                getHumidityStatusText(humidity) {
                    if (parseFloat(humidity) >= parseFloat(this.bindForm.envConfig.humidityDanger)) {
                        return '告警';
                    } else if (parseFloat(humidity) >= parseFloat(this.bindForm.envConfig.humidityWarning)) {
                        return '预警';
                    }
                    return '正常';
                },
                getOilLevelValue(oilLevel) {
                    // 从百分比转换为米制
                    const numValue = parseFloat(oilLevel);
                    if (isNaN(numValue)) return 0;
                    return (numValue / 10).toFixed(1); // 70% -> 7.0米
                },
                getOilLevelPercentage(oilLevel) {
                    const numValue = parseFloat(oilLevel);
                    if (isNaN(numValue)) return 0;
                    return (numValue / 10) * 10; // 70% -> 7.0米 -> 70%
                },
                getOilLevelStatusColor(oilLevel, deviceName) {
                    const value = this.getOilLevelValue(oilLevel);
                    const numValue = parseFloat(value);
                    
                    // 根据油箱设备的预警范围判断状态
                    // 这里使用简化的逻辑，实际应该根据绑定的预警范围配置
                    if (numValue <= 2 || numValue >= 8) {
                        return 'danger';
                    } else if (numValue <= 4 || numValue >= 6) {
                        return 'warning';
                    }
                    return 'success';
                },
                getOilLevelStatusText(oilLevel, deviceName) {
                    const value = this.getOilLevelValue(oilLevel);
                    const numValue = parseFloat(value);
                    
                    if (numValue <= 2) {
                        return '超低';
                    } else if (numValue <= 4) {
                        return '低';
                    } else if (numValue <= 6) {
                        return '正常';
                    } else if (numValue <= 8) {
                        return '高';
                    } else {
                        return '超高';
                    }
                },
                updateOilLevelFromSelect(device) {
                    // 从下拉选择更新液位值
                    const selectedValue = parseFloat(device.oilLevelInput);
                    if (!isNaN(selectedValue)) {
                        device.oilLevel = (selectedValue * 10).toString() + '%'; // 7米 -> 70%
                    }
                },
                handleAlertDoubleClick(row) {
                    this.$confirm(`确定要跳转到告警中心处理告警"${row.type}"吗？`, '处理告警', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(() => {
                        this.jumpToAlarmCenter(row);
                    }).catch(() => {
                        // 取消处理
                    });
                },
                jumpToAlarmCenter(alert) {
                    // 模拟跳转到告警中心
                    this.$message.success(`正在跳转到告警中心处理告警：${alert.type}`);
                    // 这里可以添加实际的跳转逻辑
                    // 例如：window.open('/alarm-center', '_blank');
                    console.log('跳转到告警中心处理告警:', alert);
                }
            }
        });
    </script>
</body>
</html> 